// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: xguo

#pragma once

#include <memory>
#include <sstream>
#include <string>
#include <utility>

#include "coin2/exchange/base/order/rate_tracker.h"
#include "coin2/exchange/order/connection.pb.h"

namespace coin2::exchange::binance::api_util {

class BinanceRateTracker : public coin2::exchange::base::order::IRateTracker {
 public:
  using RateTracker = coin2::exchange::base::order::RateTracker;
  using ActionType = coin2::exchange::base::order::IRateTracker::ActionType;
  using RateLimitReportWriter = coin2::exchange::base::order::RateLimitReportWriter;
  using FixedWindowRateTracker = coin2::exchange::base::order::FixedWindowRateTracker;
  using RateLimitInfoFuturesBinance = coin2::exchange::order::RateLimitInfoFuturesBinance;

 public:
  explicit BinanceRateTracker(
      const MarketExchangeApi& mea,
      const coin2::exchange::order::OrderConnectionConfig& cfg);

  void SetRateLimitInfo(int32_t rate_limit, int32_t rate_limit_remaining) override { CHECK(false); }
  void Push(int32_t num_reqs, int64_t timestamp, ActionType action_type) override;
  bool HasEnoughRateLimit(int64_t timestamp, ActionType action_type) override;
  void ParseRateLimitInfo(const std::shared_ptr<AsioHttpContext>&, ActionType) override {}
  void SetRateLimitInfoString(const google::protobuf::Message* message) override;
  void WriteRateLimitReportMessage(OrderLoggerCB callback) override;
  double GetMaxRateUsedRatio(int64_t timestamp, ActionType action_type) override;
  void UpdateReqRateInfo(const std::string& channel, void* data);
  void SetBindIp(const std::string& ip) { bind_ip_ = ip; }
  void SetEnableTime(int64_t enable_time) { enable_time_by_ip_map_[bind_ip_] = enable_time; }

 private:
  using RateTrackerType = std::unique_ptr<FixedWindowRateTracker>;
  void InitRateTracker(
      const RateLimitInfoFuturesBinance&,
      std::string_view mea_str,
      std::string_view example);
  RateTrackerType& GetReqRateTracker(const std::string& ip);
  void RetrieveRateLimitInfoByIp(
      const google::protobuf::Message& default_cfg,
      const coin2::exchange::order::OrderConnectionConfig& conn_cfg);

  bool CheckEnableTime(int64_t timestamp, ActionType action_type);
  bool CheckRateLimit(int64_t timestamp, ActionType action_type);

 private:
  const MarketExchangeApi& mea_;
  bool whitelisted_{false};
  std::unordered_map<std::string, RateTrackerType> req_rate_tracker_;
  RateTrackerType order_day_rate_tracker_ = {};
  RateTrackerType order_sec_rate_tracker_ = {};
  RateTrackerType order_min_rate_tracker_ = {};
  RateTrackerType waf_rate_tracker_ = {};

  std::unique_ptr<RateLimitReportWriter> rate_limit_report_writer_ = {};
  std::string bind_ip_;
  std::unordered_map<std::string, int64_t> enable_time_by_ip_map_;
  std::unordered_map<std::string, RateLimitInfoFuturesBinance> rate_limit_by_ip_cfg_;
};

}  // namespace coin2::exchange::binance::api_util
